﻿using ElasticSearchTest.Common;
using Nest;
using PMS.Search.Domain.Common;
using PMS.Search.Domain.Entities;
using PMS.Search.Domain.QueryModel;
using PMS.Search.Elasticsearch;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ElasticSearchTest
{
    public class CircleEsService
    {
        private readonly EsClient _client;
        private readonly EsIndexConfig.Index _index = EsIndexConfig.Instance.CircleIndex;

        public CircleEsService(EsClient client)
        {
            _client = client;
        }
        public void Test()
        {
            //var resp = CreateIndex();

            int type = 1;
            var search = SearchAsync(new SearchBaseQueryModel("测试话题", 1, 10) { 
                IsMatchAllWord = true,
                Suggestions = new List<string> { "测试话题", "加紧", "话题圈", "好" }
            }).GetAwaiter().GetResult();

            var search2 = SearchAsync(new SearchBaseQueryModel("测试", 1, 10)).GetAwaiter().GetResult();
        }

        public async Task<List<SearchCircle>> SearchAsync(SearchBaseQueryModel queryModel)
        {
            var keyword = queryModel.QueryEsKeyword;
            var orderBy = queryModel.OrderBy;
            var pageIndex = queryModel.PageIndex;
            var pageSize = queryModel.PageSize;

            int from = (pageIndex - 1) * pageSize;
            int size = pageSize;
            var search = new SearchDescriptor<SearchCircle>()
                .Index(new string[] { _index.SearchIndex })
                .Sort(sd => sd.Descending(SortSpecialField.Score).Descending(f => f.FollowCount))
                .From(from)
                .Size(size);

            var mustQuerys = new List<Func<QueryContainerDescriptor<SearchCircle>, QueryContainer>>()
            {
                q=> q.Term(t => t.Field(p => p.IsDeleted).Value(false))
            };
            var constantQuery = new ConstantScoreQuery();

            #region mustQuery

            if (queryModel.QueryEsKeywords.Any())
            {
                var innerShoulds = NestHelper.KeywordsToNest<SearchCircle>(
                    queryModel.QueryEsKeywords,
                    queryModel.IsMatchAllWord,
                    Infer.Fields("name.cntext", "userName.pinyin"),
                    Infer.Fields("name.cntext", "userName.cntext"));
                mustQuerys.Add(q => q.Bool(b => b.Should(innerShoulds)));
            }

            #endregion

            if (mustQuerys.Count != 0)
                //search.Query(q => q.Bool(b => b.Must(mustQuery)));
                search.Query(q => q.FunctionScore(csq => csq.Query(qc => qc.Bool(b => b.Must(mustQuerys)))
                    .Functions(sfd =>
                        sfd.FieldValueFactor(fff => fff.Field(f => f.FollowCount)
                        .Factor(1)
                        .Modifier(FieldValueFactorModifier.Log2P)))
                    //.ScoreMode(FunctionScoreMode.Sum)
                    .BoostMode(FunctionBoostMode.Sum)
                ));



            var result = await _client.GetClient().SearchAsync<SearchCircle>(search);
            //Debug.WriteLine(string.Join(",", result.Hits.Select(s => s.Score.ToString())));
            //Debug.WriteLine(string.Join(",", result.Hits.Select(s => s.Sorts.FirstOrDefault().ToString())));
            //Debug.WriteLine(string.Join(",", result.Hits.Select(s => s.Sorts.Skip(1).FirstOrDefault().ToString())));
            var total = result.Total;
            return result.Hits.Select(s => s.Source).ToList();
        }

        public CreateIndexResponse CreateIndex()
        {
            var resp = _client.GetClient().Indices.Delete(_index.Name);
            var createIndexResponse = _client.GetClient().Indices.Create(_index.Name, c => c
                .Aliases(ad => ad.Alias(_index.Alias))
                .Settings(s => s
                    .Setting("max_ngram_diff", 20)
                    .Setting("max_result_window", 500000)
                    .Analysis(AnalyzeBuilder.GetAnalysis())
                )
                .Map<SearchCircle>(mm => mm
                .Dynamic(false)
                   .Properties(p => p
                       .Keyword(t => t.Name(n => n.Id))
                       .Keyword(t => t.Name(n => n.UserId))
                       .Date(t => t.Name(n => n.CreateTime))
                       .Date(t => t.Name(n => n.ModifyTime))
                       .Boolean(t => t.Name(n => n.IsDisable))
                       .Boolean(t => t.Name(n => n.IsDeleted))
                       .Number(t => t.Name(n => n.FollowCount))
                       .Number(t => t.Name(n => n.Pv))
                       .Number(t => t.Name(n => n.Uv))
                       .Text(t => t
                           .Name(n => n.Name)
                           .Fields(f => f
                                .Text(ft
                                    => ft.Name("cntext")
                                    .Analyzer(AnalyzeBuilder.IkNgramAnalyzer)
                                    .SearchAnalyzer(AnalyzeBuilder.IkSearchAnalyzer))
                                .Text(ft
                                    => ft.Name("pinyin")
                                    .Analyzer(AnalyzeBuilder.IkPinyinAnalyzer)
                                    .SearchAnalyzer(AnalyzeBuilder.IkPinyinSearchAnalyzer))
                                .Text(ft
                                    => ft.Name("keyword")
                                    .Analyzer(AnalyzeBuilder.KeywordPinyinNgramAnalyzer)
                                    .SearchAnalyzer(AnalyzeBuilder.IkSearchAnalyzer))
                           )
                           .IndexOptions(IndexOptions.Docs)
                       )
                       .Text(t => t
                           .Name(n => n.UserName)
                           .Fields(f => f
                                .Text(ft
                                    => ft.Name("cntext")
                                    .Analyzer(AnalyzeBuilder.IkNgramAnalyzer)
                                    .SearchAnalyzer(AnalyzeBuilder.IkSearchAnalyzer))
                                .Text(ft
                                    => ft.Name("pinyin")
                                    .Analyzer(AnalyzeBuilder.IkPinyinAnalyzer)
                                    .SearchAnalyzer(AnalyzeBuilder.IkPinyinSearchAnalyzer))
                                .Text(ft
                                    => ft.Name("keyword")
                                    .Analyzer(AnalyzeBuilder.KeywordPinyinNgramAnalyzer)
                                    .SearchAnalyzer(AnalyzeBuilder.IkSearchAnalyzer))
                           )
                           .IndexOptions(IndexOptions.Docs)
                       )
                       .FieldAlias(fa => fa.Name("talentUserName.pinyin").Path("userName.pinyin"))
                       //.FieldAlias(fa => fa.Name("talentUserName").Path("userName")) //必须小写,  这里不会自动小写
                       .Text(t => t
                           .Name(n => n.Intro)
                           .Fields(f => f.Text(ft
                                 => ft.Name("pinyin")
                                .Analyzer(AnalyzeBuilder.IkPinyinAnalyzer)
                                .SearchAnalyzer(AnalyzeBuilder.IkPinyinSearchAnalyzer)
                           ))
                       )
                      .Number(t => t.Name(n => n.Pv))
                      .Number(t => t.Name(n => n.Uv))
                   )
               )
            );
            return createIndexResponse;
        }
    }
}
